package com.lucenten.collect.exec;

import cn.quevo.common.file.FileUtils;
import cn.quevo.common.lang.StringUtils;
import com.lucenten.collect.Context;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.file.Path;
import java.util.List;

/**
 * 执行Shell
 */
@Slf4j
public class ShellRun {
    /**
     * 需要输出文件<p/>
     * 比如：
     * <pre>
     *
     *     Path infoFile = Paths.get(infoPath,"stationinfo_"+gnssFile.getStationId()+stationName+".txt");
     *         FileUtils.createDirs(infoFile);
     *         boolean isSuccess = ShellRun.execOutPut("teqc +meta "+file.normalize().toString(), infoFile);
     * </pre>
     * <pre>
     *      String commond = TEQC_RUN + " -tr do -week " + gnssFile.getDate().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
     *         commond += " +nav " + super.getUnZipPath(gnssFile, saveName + "n").normalize().toString() + " " + dPath.normalize().toString();
     *
     *         Path oPath = Paths.get(super.getTempPath("o", gnssFile), saveName + "o");
     *         ShellRun.execOutPut(commond, oPath);
     * </pre>
     *
     * @param commond 执行命令
     * @param target  输出文件路径
     * @return
     */
    public static boolean execOutPut(String commond, Path target) {
        if (StringUtils.isBlank(commond)) {
            return false;
        }
        FileUtils.createAndNotExists(target.getParent());
        log.info("RUN EXE " + commond + target.normalize().toString());
        try (FileOutputStream outputStream = new FileOutputStream(target.normalize().toFile());) {
            return execOutPut(commond, outputStream);
        } catch (FileNotFoundException e) {
            log.error("文件不存在", e);
        } catch (IOException e) {
            log.error("命令执行失败，文件无法写入", e);
        }
        return false;
    }

    public static boolean execOutPut(String commond) {
        try (OutputStream outputStream = new ByteArrayOutputStream();) {
            return execOutPut(commond, outputStream);
        } catch (IOException e) {
            log.error("命令执行失败，文件无法写入", e);
        }
        return false;
    }

    /**
     * 执行SHELL脚本，需要输入文件
     *
     * @param commond      执行命令
     * @param outputStream 输出流
     * @return
     */
    public static boolean execOutPut(String commond, OutputStream outputStream) {
        if (StringUtils.isBlank(commond)) {
            return false;
        }
        String[] commonds = new String[3];
        if (Context.isWindows()) {
            commonds[0] = "CMD";
            commonds[1] = "/C";
        } else {
            commonds[0] = "/bin/bash";
            commonds[1] = "-c";
        }
        commonds[2] = commond;
        try {
            Process process = Runtime.getRuntime().exec(commonds);
            // 重定向输出流和错误流
            ShellStream error = new ShellStream(process.getErrorStream(), "error");
            ShellStream out = new ShellStream(process.getInputStream(), outputStream, "output", "GBK");
            error.start();
            out.start();
            int status = process.waitFor();
            return status == 0;
        } catch (FileNotFoundException e) {
            log.error("命令执行失败，文件不存在", e);
        } catch (IOException e) {
            log.error("命令执行失败，文件无法写入", e);
        } catch (InterruptedException e) {
            log.error("命令执行失败，文件无法写入", e);
        }
        return false;
    }

    /**
     * 执行Shell脚本，不需要输出文件
     *
     * @param commond
     * @return
     */
    public static boolean exec(List<String> commond) {
        if (!StringUtils.isBlank(commond)) {
            return true;
        }
        if (StringUtils.isEmpty(commond)) {
            return false;
        }
        try {
            if (Context.isWindows()) {
                commond.add(0, "/C");
                commond.add(0, "CMD");
            } else {
                commond.add(0, "-c");
                commond.add(0, "/bin/bash");
            }
//            commond.add("exit");
            String[] cmds = new String[commond.size()];
            commond.toArray(cmds);
            Process process = Runtime.getRuntime().exec(cmds);
            return process.waitFor() == 0;
        } catch (IOException e) {
            log.error("SHELL 命令执行失败：" + e.toString(), e);
        } catch (InterruptedException e) {
            log.error("命令执行失败，文件无法写入", e);
        }
        return false;
    }
}
